package com.boot.system.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.ds.simple.SimpleDataSource;
import cn.hutool.db.meta.Column;
import cn.hutool.db.meta.MetaUtil;
import cn.hutool.db.meta.Table;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.boot.common.property.DataSourceProperties;
import com.boot.system.entity.SysModule;
import com.boot.system.service.DatabaseService;
import com.boot.util.DbFieldUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据库操作
 */
@Slf4j
@RequiredArgsConstructor
@Service("databaseService")
public class DatabaseServiceImpl implements DatabaseService {

    private final DataSourceProperties dataSourceProperties;

    @Override
    public void createTable(SysModule sysModule) {
        String tableName = StrUtil.format("tb_{}", StrUtil.toUnderlineCase(sysModule.getMid()));
        StringBuilder sql = new StringBuilder();
        sql.append("CREATE TABLE IF NOT EXISTS `");
        sql.append(tableName);
        sql.append("` (");

        JSONArray tableJson = JSONUtil.parseArray(sysModule.getTableJson());
        for (int i = 0; i < tableJson.size(); i++) {
            JSONObject item = tableJson.getJSONObject(i);
            if (ObjectUtil.isEmpty(item.get("name"))){
                continue;
            }
            if ("id".equals(item.getStr("name"))) {
                // 自增ID
                sql.append("`id` bigint(20) PRIMARY KEY AUTO_INCREMENT");
            } else if ("create_by".equals(item.getStr("name"))) {
                // 创建人
                sql.append("`create_by` bigint(20) NULL");
            } else if ("create_time".equals(item.getStr("name"))) {
                // 创建时间
                sql.append("`create_time` bigint(20) NULL");
            } else if ("update_by".equals(item.getStr("name"))) {
                // 更新人
                sql.append("`update_by` bigint(20) NULL");
            } else if ("update_time".equals(item.getStr("name"))) {
                // 更新时间
                sql.append("`update_time` bigint(20) NULL");
            } else if ("is_deleted".equals(item.getStr("name"))) {
                // 逻辑删除
                sql.append("`is_deleted` tinyint(1) NOT NULL");
            } else {
                // 其他字段
                sql.append(StrUtil.format("`{}` {} NULL", item.getStr("name"), DbFieldUtil.getMysqlFieldType(item.getStr("type"))));
            }
            // 最后一个字段不添加逗号
            if (i != tableJson.size() - 1) {
                sql.append(",");
            }
        }

        sql.append(") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

        // 连接数据库，并执行任务
        try (SimpleDataSource ds = new SimpleDataSource(dataSourceProperties.getMysql().getUrl(), dataSourceProperties.getMysql().getUsername(), dataSourceProperties.getMysql().getPassword())) {
            Db db = Db.use(ds);
            try {
                db.execute(sql.toString());
            } catch (SQLException e) {
                log.error("CreateTable", e);
            }
        } catch (Exception e) {
            log.error("CreateTable", e);
        }
    }

    @Override
    public void updateTable(SysModule sysModule) {
        String tableName = StrUtil.format("tb_{}", StrUtil.toUnderlineCase(sysModule.getMid()));
        JSONArray tableJson = JSONUtil.parseArray(sysModule.getTableJson());
        // 字段列表
        List<String> fields = new ArrayList<>();
        // 字段类型映射
        Map<String, String> fieldMap = new HashMap<>();
        for (int i = 0; i < tableJson.size(); i++) {
            JSONObject item = tableJson.getJSONObject(i);
            if (ObjectUtil.isEmpty(item.get("name"))){
                continue;
            }
            fields.add(item.getStr("name"));
            fieldMap.put(item.getStr("name"), item.getStr("type"));
        }
        // 连接数据库，并执行任务
        try (SimpleDataSource ds = new SimpleDataSource(dataSourceProperties.getMysql().getUrl(), dataSourceProperties.getMysql().getUsername(), dataSourceProperties.getMysql().getPassword())) {
            Db db = Db.use(ds);
            Table table = MetaUtil.getTableMeta(db.getDs(), tableName);
            // 删除字段
            for (Column column : table.getColumns()) {
                if (!fields.contains(column.getName())) {
                    // 如果字段不存在了则删掉
                    String sql = StrUtil.format("ALTER TABLE {} DROP COLUMN {}", tableName, column.getName());
                    try {
                        db.execute(sql);
                    } catch (SQLException e) {
                        log.error("删除字段，{} -> {}", tableName, column.getName(), e);
                    }
                }
            }
            // 添加字段
            for (String field : fields) {
                if (table.getColumn(field) == null) {
                    // 如果字段不存则添加字段
                    String sql = StrUtil.format("ALTER TABLE {} ADD COLUMN {} {}", tableName, field, DbFieldUtil.getMysqlFieldType(fieldMap.get(field)));
                    try {
                        db.execute(sql);
                    } catch (SQLException e) {
                        log.error("添加字段，{} -> {}", tableName, field, e);
                    }
                }
            }
        } catch (Exception e) {
            log.error("UpdateTable", e);
        }
    }
}
